package com.atguigu.tingshu.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.account.client.UserAccountFeignClient;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.TrackInfoFeignClient;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.user.VipServiceConfig;
import com.atguigu.tingshu.order.helper.SignHelper;
import com.atguigu.tingshu.order.mapper.OrderDerateMapper;
import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.user.client.VipServiceConfigFeignClient;
import com.atguigu.tingshu.vo.account.AccountDeductVo;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Autowired
    private VipServiceConfigFeignClient vipServiceConfigFeignClient;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private TrackInfoFeignClient trackInfoFeignClient;

    @Autowired
    private RabbitService rabbitService;

    @Autowired
    private UserAccountFeignClient userAccountFeignClient;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private OrderDerateMapper orderDerateMapper;


    /**
     * @author WeakMoon
     * @date 2025/03/07 17:10:57
     * 生成订单详情页
     */
    @Override
    public OrderInfoVo trade(TradeVo tradeVo, Long userId) {
        /**
         * @author WeakMoon
         * @date 2025/03/07 17:18:22
         * 给orderinfovo里的属性赋值
         */
        //订单原始金额
        BigDecimal originalAmount = new BigDecimal("0.00");
        //减免总金额
        BigDecimal derateAmount = new BigDecimal("0.00");
        //订单总金额
        BigDecimal orderAmount = new BigDecimal("0.00");
        //订单明细列表
        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
        //订单减免明细列表
        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();

        //判断订单付款项目类型
        if (SystemConstant.ORDER_ITEM_TYPE_ALBUM.equals(tradeVo.getItemType())){
            //专辑
            Long albumId = tradeVo.getItemId();
            //判断用户是否购买过此专辑
            Result<Boolean> result = userInfoFeignClient.isPaidAlbum(albumId);
            Assert.notNull(result,"远程调用判断用户是否购买过专辑失败");
            if (result.getData()){
                throw new RuntimeException("用户已购买过此专辑");
            }

            Result<AlbumInfo> infoResult = albumInfoFeignClient.getAlbumInfo(albumId);
            Assert.notNull(infoResult,"远程调用获取专辑信息失败");
            AlbumInfo albumInfo = infoResult.getData();
            Assert.notNull(albumInfo,"远程调用专辑信息失败");
            //得到订单原始金额
            originalAmount = albumInfo.getPrice();

            Result<UserInfoVo> infoVoResult = userInfoFeignClient.getUserInfo(userId);
            Assert.notNull(infoResult,"远程调用获取用户信息失败");
            UserInfoVo userInfoVo = infoVoResult.getData();
            Assert.notNull(userInfoVo,"远程调用用户信息失败");
            //得到减免总金额
            if (0 == userInfoVo.getIsVip() || (1 == userInfoVo.getIsVip() && userInfoVo.getVipExpireTime().before(new Date()))){
                //普通用户
                if (albumInfo.getDiscount().compareTo( new BigDecimal("-1")) != 0){
                    //有折扣 1000*（10-8）/10
                    derateAmount = originalAmount.multiply(new BigDecimal("10").subtract(albumInfo.getDiscount())).divide(new BigDecimal("10"),2,BigDecimal.ROUND_HALF_UP);
                }
            } else {
                //VIP用户
                if (albumInfo.getDiscount().compareTo( new BigDecimal("-1")) != 0){
                    //有折扣
                    derateAmount = originalAmount.multiply(new BigDecimal("10").subtract(albumInfo.getDiscount())).divide(new BigDecimal("10"),2,BigDecimal.ROUND_HALF_UP);
                }
            }
            //得到订单总金额
            orderAmount = originalAmount.subtract(derateAmount);

            //订单明细列表赋值
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(tradeVo.getItemId());
            orderDetailVo.setItemName(albumInfo.getAlbumTitle());
            orderDetailVo.setItemPrice(orderAmount);
            orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
            orderDetailVoList.add(orderDetailVo);

            //订单减免明细列表赋值
            OrderDerateVo orderDerateVo = new OrderDerateVo();
            if (derateAmount.compareTo(new BigDecimal("0")) != 0) {
                orderDerateVo.setDerateAmount(derateAmount);
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_ALBUM_DISCOUNT);
                orderDerateVo.setRemarks("专辑折扣");
                orderDerateVoList.add(orderDerateVo);
            }

        }else if (SystemConstant.ORDER_ITEM_TYPE_TRACK.equals(tradeVo.getItemType())){
            //声音
            //判断购买集数，0是本集，但绝对不能小于0
            if (tradeVo.getTrackCount() < 0){
                throw new RuntimeException("购买集数不能小于0");
            }

            //给属性（订单原始金额、订单总金额、订单明细列表）赋值，声音不支持折扣
            //通过声音id远程调用获取声音对象，再通过声音对象获取专辑id
            // Result<TrackInfo> trackInfoResult = TrackInfoFeignClient.getTrackInfo(tradeVo.getItemId());
            // Assert.notNull(trackInfoResult,"远程调用获取声音对象失败");
            // TrackInfo trackInfo = trackInfoResult.getData();
            // Assert.notNull(trackInfo,"远程调用声音对象失败");
            // Long albumId = trackInfo.getAlbumId();

            //订单明细列表 每一集声音的明细（价格，标题，图片等信息）
            Result<List<TrackInfo>> trackInfoListResult = trackInfoFeignClient.findPaidTrackInfoList(tradeVo.getItemId(), tradeVo.getTrackCount());
            Assert.notNull(trackInfoListResult,"远程调用批量获取下单付费声音列表失败");
            List<TrackInfo> trackInfoList = trackInfoListResult.getData();
            Assert.notNull(trackInfoList,"远程调用下单付费列表失败");

            //获取专辑对象
            Result<AlbumInfo> infoResult = albumInfoFeignClient.getAlbumInfo(trackInfoList.get(0).getAlbumId());
            Assert.notNull(infoResult,"远程调用获取专辑对象失败");
            AlbumInfo albumInfo = infoResult.getData();
            Assert.notNull(albumInfo,"远程获取专辑对象失败");

            //订单原始金额 = 订单总金额 = 单价*数量
            originalAmount = tradeVo.getTrackCount() == 0 ? albumInfo.getPrice() : albumInfo.getPrice().multiply(new BigDecimal(tradeVo.getTrackCount()));
            orderAmount = originalAmount;

            //循环遍历下单付费声音列表并赋值给orderDetailVo，组成一个新的集合
            orderDetailVoList = trackInfoList.stream().map(trackInfo1 -> {
                OrderDetailVo orderDetailVo = new OrderDetailVo();
                orderDetailVo.setItemId(trackInfo1.getId());
                orderDetailVo.setItemName(trackInfo1.getTrackTitle());
                orderDetailVo.setItemPrice(albumInfo.getPrice());
                orderDetailVo.setItemUrl(trackInfo1.getCoverUrl());
                //返回结果数据
                return orderDetailVo;
            }).collect(Collectors.toList());

        }else if (SystemConstant.ORDER_ITEM_TYPE_VIP.equals(tradeVo.getItemType())){
            //VIP
            Long itemId = tradeVo.getItemId();
            Result<VipServiceConfig> serviceConfigResult = vipServiceConfigFeignClient.getVipServiceConfig(itemId);
            Assert.notNull(serviceConfigResult,"远程调用获取vip_service_config对应大数据失败");
            VipServiceConfig vipServiceConfig = serviceConfigResult.getData();
            Assert.notNull(vipServiceConfig,"远程调用大数据失败");

            //订单原始金额
            originalAmount = vipServiceConfig.getPrice();

            //减免总金额
            derateAmount = originalAmount.subtract(vipServiceConfig.getDiscountPrice());

            //订单总金额
            orderAmount = vipServiceConfig.getDiscountPrice();

            //订单明细列表赋值
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(itemId);
            orderDetailVo.setItemName(vipServiceConfig.getName());
            orderDetailVo.setItemPrice(orderAmount);
            orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl());
            orderDetailVoList.add(orderDetailVo);

            //订单减免明细列表赋值
            OrderDerateVo orderDerateVo = new OrderDerateVo();
            if (derateAmount.compareTo(new BigDecimal("0")) != 0) {
                orderDerateVo.setDerateAmount(derateAmount);
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT);
                orderDerateVo.setRemarks("VIP折扣");
                orderDerateVoList.add(orderDerateVo);
            }

        }

        OrderInfoVo orderInfoVo = new OrderInfoVo();

        String tradeNo = UUID.randomUUID().toString().replaceAll("-","");
        String tradeNoKey = "tradeNo:" + userId + ":" + tradeNo;
        this.redisTemplate.opsForValue().setIfAbsent(tradeNoKey,tradeNo,15, TimeUnit.MINUTES);
        orderInfoVo.setTradeNo(tradeNo);
        //支付方式默认为空
        orderInfoVo.setPayWay("");
        orderInfoVo.setItemType(tradeVo.getItemType());
        orderInfoVo.setOriginalAmount(originalAmount);
        orderInfoVo.setDerateAmount(derateAmount);
        orderInfoVo.setOrderAmount(orderAmount);
        orderInfoVo.setOrderDetailVoList(orderDetailVoList);
        orderInfoVo.setOrderDerateVoList(orderDerateVoList);
        //自定义时间戳
        long timestamp = SignHelper.getTimestamp();
        orderInfoVo.setTimestamp(timestamp);
        //自定义签名，保证接口不被篡改,保证接口安全性
        String sign = SignHelper.getSign(JSON.parseObject(JSON.toJSONString(orderInfoVo), Map.class));
        orderInfoVo.setSign(sign);

        return orderInfoVo;
    }

    /**
     * @author WeakMoon
     * @date 2025/03/09 22:21:37
     * 提交订单
     */
    @Override
    public String submitOrder(OrderInfoVo orderInfoVo, Long userId) {
        //将orderInfoVo转成map
        Map map = JSON.parseObject(JSON.toJSONString(orderInfoVo), Map.class);
        //将支付方式变""
        map.put("payWay","");
        //校验签名
        SignHelper.getSign(map);
        //防止重复提交订单 获取页面流水号
        String tradeNo = orderInfoVo.getTradeNo();
        //与缓存流水号进行对比
        String tradeNoKey = "tradeNo:" + userId + ":" + tradeNo;
        //定义lua脚本
        String screptText = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
                "then\n" +
                "    return redis.call(\"del\",KEYS[1])\n" +
                "else\n" +
                "    return 0\n" +
                "end";

        //  当键值与口令串一致的时候就删除数据;
        //  创建RedisScript对象;
        DefaultRedisScript<Long> script = new DefaultRedisScript<>();
        script.setResultType(Long.class);
        script.setScriptText(screptText);
        Long count = (Long) redisTemplate.execute(script, Arrays.asList(tradeNoKey), tradeNo);

        if (count == 0){
            //删除失败，页面与缓存的值不相等，订单重复提交
            throw new RuntimeException("重复提交订单");
        }

        //声明一个订单号
        String orderNo = UUID.randomUUID().toString().replaceAll("-","");

        //判断支付方式
        if (!SystemConstant.ORDER_PAY_ACCOUNT.equals(orderInfoVo.getPayWay())){
            //在线支付
            //保存订单
            this.saveOrder(userId,orderNo,orderInfoVo);

            //发送延迟消息
            rabbitService.sendDealyMessage(MqConst.EXCHANGE_ORDER,MqConst.ROUTING_CANCEL_ORDER,orderNo,MqConst.CANCEL_ORDER_DELAY_TIME);

        }else {
            //余额支付
            //保存订单
            this.saveOrder(userId,orderNo,orderInfoVo);
            //扣减余额
            AccountDeductVo accountDeductVo = new AccountDeductVo();
            accountDeductVo.setOrderNo(orderNo);
            accountDeductVo.setUserId(userId);
            accountDeductVo.setAmount(orderInfoVo.getOrderAmount());
            accountDeductVo.setContent(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
            //实现远程调用
            Result result = userAccountFeignClient.checkAndDeduct(accountDeductVo);

            //记录当前用户购买信息
            if (200 != result.getCode()){
                throw new RuntimeException("扣减余额失败");
            }

            //扣减成功，更新订单状态
            OrderInfo orderInfo = new OrderInfo();
            orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_PAID);
            orderInfo.setUpdateTime(new Date());
            //修改订单状态
            orderInfoMapper.update(orderInfo,new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo,orderNo));

            //保存用户购买记录
            //  构建实体类：
            UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
            userPaidRecordVo.setOrderNo(orderNo);
            userPaidRecordVo.setUserId(userId);
            //  用它来判断用户具体购买的内容：
            userPaidRecordVo.setItemType(orderInfoVo.getItemType());
            //  itemIdList 购买类型Id; 从哪里来? 页面传递的 声音Id, 专辑Id ，vipId;都在 orderDetailVoList 这个集合中！
            //  如果购买专辑,vip的话；这个集合中 orderDetailVoList 只有一条记录; 购买声音的话，这个集合中orderDetailVoList 有多条记录;
            List<Long> itemIdList = orderInfoVo.getOrderDetailVoList().stream().map(OrderDetailVo::getItemId).collect(Collectors.toList());
            userPaidRecordVo.setItemIdList(itemIdList);
            //  远程调用：
            Result userResult = userInfoFeignClient.savePaidRecord(userPaidRecordVo);
            //  判断用户购买记录保存成功;
            if (200 != userResult.getCode()) {
                //  出现异常
                throw new RuntimeException("保存用户购买记录失败");
            }
        }
        //返回数据
        return orderNo;
    }

    /**
     * @author WeakMoon
     * @date 2025/03/10 16:29:25
     * 保存订单信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveOrder(Long userId, String orderNo, OrderInfoVo orderInfoVo) {
        OrderInfo orderInfo = new OrderInfo();

        //属性拷贝
        BeanUtils.copyProperties(orderInfoVo,orderInfo);
        //赋值用户Id
        orderInfo.setUserId(userId);
        //订单标题
        orderInfo.setOrderTitle(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
        //订单编号
        orderInfo.setOrderNo(orderNo);
        //保存订单
        orderInfoMapper.insert(orderInfo);
        //保存订单明细
        //获取订单明细
        List<OrderDetailVo> orderDetailVoList = orderInfoVo.getOrderDetailVoList();
        //只有购买声音时，这个集合有可能是多条数据
        //订单中的itemid可能是专辑id，声音id，vipid
        if (!CollectionUtils.isEmpty(orderDetailVoList)){
            //循环遍历
            for (OrderDetailVo orderDetailVo : orderDetailVoList) {
                //创建对象
                OrderDetail orderDetail = new OrderDetail();
                //属性拷贝
                BeanUtils.copyProperties(orderDetailVo,orderDetail);
                orderDetail.setOrderId(orderInfo.getId());
                //保存数据
                orderDetailMapper.insert(orderDetail);

            }
        }
        //减免
        List<OrderDerateVo> orderDerateVoList = orderInfoVo.getOrderDerateVoList();
        if (!CollectionUtils.isEmpty(orderDerateVoList)){
            //循环遍历
            for (OrderDerateVo orderDerateVo : orderDerateVoList) {
                //创建对象
                OrderDerate orderDerate = new OrderDerate();
                //属性拷贝
                BeanUtils.copyProperties(orderDerateVo, orderDerate);
                orderDerate.setOrderId(orderInfo.getId());
                //保存数据
                orderDerateMapper.insert(orderDerate);
            }

        }
    }
}
